import React, { ReactNode, useCallback, useEffect, useReducer, useState } from 'react';
import { AiOutlineMore } from 'react-icons/ai';
import cls from './ReportTree.module.less';
import { schema } from '@/utils/excel';
import { Breadcrumb, Button, message, Modal, Popover, Row, Tree } from 'antd';
import { ReportTaskTreeNodeView } from '@/ts/base/model';
import { getStatus, ReceptionStatus } from '@/ts/core/work/assign/reception/status';
import _ from 'lodash';
import { IReportTree } from '@/ts/core';
import ReportTreeNodeModal from './itemModal';
import { AssignStatusType, NodeType } from '@/ts/base/enum';

interface IProps<T extends schema.XReportTreeNode> {
  nodes: T[];
  current?: IReportTree;
  onCheck?: (
    checked: React.Key[] | { checked: React.Key[]; halfChecked: React.Key[] },
    info: any,
  ) => void;
  onSelect?: (selectedKeys: React.Key[], info: any) => void;
  onExpand?: (expandedKeys: React.Key[]) => void;
  expandedKeys?: React.Key[];
  selectedKeys?: React.Key[];
  checkable?: boolean;
  renderNode?: (node: T) => ReactNode;
  loadChildren?: (parentNodeId: string) => Promise<T[]>;
  currentTag?: string;
  searchText?: string;
  type?: string;
  externalField?: any;
  curRootNodeId?: string;
}

interface TreeState<T> {
  selectedKeys: React.Key[];
  expandedKeys: React.Key[];
  treeData: T[];
  filterTreeData: T[];
}

const initialState: TreeState<schema.XReportTreeNode> = {
  selectedKeys: [],
  expandedKeys: [],
  treeData: [],
  filterTreeData: [],
};

const treeReducer = <T extends schema.XReportTreeNode>(
  state: TreeState<T>,
  action: any,
): TreeState<T> => {
  switch (action.type) {
    case 'SET_SELECTED_KEYS':
      return { ...state, selectedKeys: action.payload };
    case 'SET_EXPANDED_KEYS':
      return { ...state, expandedKeys: action.payload };
    case 'SET_TREE_DATA':
      return { ...state, treeData: action.payload };
    case 'SET_FILTER_TREE_DATA':
      return { ...state, filterTreeData: action.payload };
    default:
      return state;
  }
};

function isMatchStatus(s: ReceptionStatus, currentTag: string | undefined) {
  if (currentTag === 'total') return true;
  if (currentTag === AssignStatusType.RECEIVED)
    return s === AssignStatusType.RECEIVED || s === AssignStatusType.ASSIGNED;
  if (currentTag === AssignStatusType.SUBMITTED)
    return (
      s === AssignStatusType.SUBMITTED ||
      s === AssignStatusType.CHANGED ||
      s === AssignStatusType.REJECTED
    );
  return s === currentTag;
}

const ReportTree = <T extends schema.XReportTreeNode = schema.XReportTreeNode>(
  props: IProps<T>,
) => {
  const [state, dispatch] = useReducer(treeReducer, initialState);
  const { selectedKeys, expandedKeys, treeData, filterTreeData } = state;
  const [activeModel, setActiveModel] = useState<string>('');
  const [curRootNodeId, setCurRootNodeId] = useState(props.curRootNodeId ?? '');
  const [item, setItem] = useState<schema.XReportTreeNode>();
  const [parentId, setParentId] = useState('');
  const [adjustmentNodeMap, setAdjustmentNodeMap] = useState<
    Dictionary<schema.XReportTreeNode>
  >({});

  const loopFilterTree = (data: ReportTaskTreeNodeView[], ids: string[]) => {
    const result: ReportTaskTreeNodeView[] = [];
    for (const item of data) {
      const newItem = { ...item };
      let s: any = getStatus(item.reception);
      if (props.type) {
        s = item.taskStatus || 'empty';
      }
      let exsit = isMatchStatus(s, props.currentTag);
      if (exsit && item.reception?.instanceId) {
        ids.push(item.reception.instanceId);
      }
      if (!item.isLeaf) {
        const find = loopFilterTree(newItem.children ?? [], ids);
        if (props.searchText != null) {
          exsit = exsit && newItem.name.includes(props.searchText);
        }
        exsit = exsit || find.length > 0;
        newItem.children = find;
      } else {
        newItem.children = [];
        if (props.searchText != null) {
          exsit = exsit && newItem.name.includes(props.searchText);
        }
      }

      if (exsit) {
        result.push(newItem);
      }
    }
    return result;
  };

  useEffect(() => {
    const ids: string[] = [];
    const filteredTreeData = loopFilterTree(treeData as any, ids);
    dispatch({ type: 'SET_FILTER_TREE_DATA', payload: filteredTreeData });
  }, [props.currentTag, props.searchText, treeData]);

  const updateTreeData = (nodes: T[], treeParentId: string, children: T[]): T[] => {
    return nodes.map((node) => {
      if (node.id === treeParentId) {
        return { ...node, children: children ?? [] };
      }
      if (node.children) {
        return {
          ...node,
          children: updateTreeData(node.children as T[], treeParentId, children),
        };
      }
      return node;
    });
  };

  const loadTreeData = useCallback(
    async (node: T) => {
      if (props.loadChildren) {
        const children = await props.loadChildren(node.id);
        children.forEach((child) => {
          child.isLeaf = child.nodeType === NodeType.Normal;
        });
        dispatch({
          type: 'SET_TREE_DATA',
          payload: updateTreeData(treeData as T[], node.id, children),
        });
      }
    },
    [props.loadChildren, treeData],
  );

  const handleExpand = useCallback(
    (keys: React.Key[]) => {
      dispatch({ type: 'SET_EXPANDED_KEYS', payload: keys });
      props?.onExpand?.(keys);
    },
    [props.onExpand],
  );

  const handleSelect = useCallback(
    (keys: React.Key[], info: any) => {
      dispatch({ type: 'SET_SELECTED_KEYS', payload: keys });
      props?.onSelect?.(keys, info);
      const node = info.node as T;
      if (props.loadChildren && node) {
        loadTreeData(node);
      }
    },
    [props.onSelect, props.loadChildren, loadTreeData],
  );

  const loadNodes = useCallback(async () => {
    if (props.current) {
      if (props.type) {
        const nodes =
          curRootNodeId === ''
            ? await props.current.loadNodes()
            : await props.current.loadSubNodes(curRootNodeId, true);
        const treeData = buildTree(nodes as T[]);
        dispatch({ type: 'SET_TREE_DATA', payload: treeData });
      } else {
        try {
          let nodes: T[] = [];
          if (props.current.metadata.rootNodeId) {
            await props.current.loadNodeById([props.current.metadata.rootNodeId]);
            nodes = props.current.nodes as T[];
          } else {
            nodes = (await props.current.loadNodes()) as T[];
          }
          dispatch({ type: 'SET_TREE_DATA', payload: nodes });
        } catch (error) {
          console.error('加载节点数据失败:', error);
        }
      }
    }
  }, [props.current]);

  const handleActionClick = useCallback(
    async (action: string, node: T) => {
      // 检查是否是根节点
      const isRootNode = node.id === props.curRootNodeId;

      switch (action) {
        case '编辑':
          if (isRootNode) {
            message.warning('您不能编辑该节点的信息');
            return;
          }
          setItem(node);
          setActiveModel('edit');
          break;
        case '新增':
          setItem(node);
          setActiveModel('add');
          break;
        case '调整':
          if (isRootNode) {
            message.warning('您不能调整该节点的上下级');
            return;
          }
          setItem(node);
          setParentId('');
          setActiveModel('parent');
          break;
        case '删除':
          if (isRootNode) {
            message.warning('您不能删除该节点');
            return;
          }
          Modal.confirm({
            content: '确实要删除所选节点及其下级吗？',
            onOk: async () => {
              await props.current?.deleteNode(node);
              loadNodes();
            },
          });
          break;
        default:
          break;
      }
    },
    [loadNodes, props.current, props.curRootNodeId],
  );
  const [openPopoverNodeId, setOpenPopoverNodeId] = useState<string | null>(null);
  const treeTitleRender = useCallback(
    (node: T) => {
      const handleClosePopover = () => {
        setOpenPopoverNodeId(null);
      };

      const content = (
        <div className={cls['btn-content']}>
          <Button
            type="text"
            block
            onClick={() => {
              handleActionClick('编辑', node);
              handleClosePopover();
            }}>
            编辑节点
          </Button>
          <Button
            type="text"
            block
            onClick={() => {
              handleActionClick('新增', node);
              handleClosePopover();
            }}>
            新增子节点
          </Button>
          <Button
            type="text"
            block
            onClick={() => {
              handleActionClick('调整', node);
              handleClosePopover();
            }}>
            调整上下级
          </Button>
          <Button
            type="text"
            danger
            block
            onClick={() => {
              handleActionClick('删除', node);
              handleClosePopover();
            }}>
            删除节点
          </Button>
        </div>
      );
      return (
        <div className={cls['tree-title-wrapper']}>
          <div className={cls['tree-title']}>{props.renderNode?.(node) ?? node.name}</div>
          {props.checkable && (
            <Popover
              content={content}
              trigger="click"
              placement="bottomRight"
              open={openPopoverNodeId === node.id}
              onOpenChange={(visible) => {
                if (visible) {
                  setOpenPopoverNodeId(node.id);
                } else {
                  setOpenPopoverNodeId(null);
                }
              }}>
              <AiOutlineMore className={cls['more-button']} />
            </Popover>
          )}
        </div>
      );
    },
    [handleActionClick, props.renderNode, openPopoverNodeId],
  );

  function buildTree<T extends schema.XReportTreeNode>(data: T[]): T[] {
    const map: Record<string, T> = {};
    data.forEach((item) => {
      item.isLeaf = item.nodeType == NodeType.Normal;
      map[item.id] = { ...item, children: [] };
    });

    const result: T[] = [];
    data.forEach((item) => {
      if (item.parentId && map[item.parentId]) {
        map[item.parentId].children?.push(map[item.id]);
      } else {
        result.push(map[item.id]);
      }
    });
    return result;
  }

  useEffect(() => {
    if (props.type) {
      const nodes = buildTree(props.nodes);
      setCurRootNodeId(nodes[0].id);
      dispatch({ type: 'SET_TREE_DATA', payload: nodes });
    } else {
      dispatch({ type: 'SET_TREE_DATA', payload: props.nodes });
    }
  }, [props.nodes]);

  const getBreadcrumbPath = (currentId: string): schema.XReportTreeNode[] => {
    const path: schema.XReportTreeNode[] = [];
    let currentNode = adjustmentNodeMap[currentId];
    while (currentNode) {
      path.unshift(currentNode);
      if (!currentNode.parentId) break;
      currentNode = adjustmentNodeMap[currentNode.parentId];
    }
    return path;
  };

  const loadReportTreeNodeModal = () => {
    if (!item) return null;

    const commonModalProps = {
      open: true,
      onCancel: () => {
        setActiveModel('');
        setItem(undefined);
      },
    };

    switch (activeModel) {
      case 'add':
        return (
          <ReportTreeNodeModal
            open
            data={item}
            current={props.current!}
            typeName={props.current?.typeName!}
            operateType="add"
            handleCancel={() => {
              setActiveModel('');
              setItem(undefined);
            }}
            handleOk={(success: boolean) => {
              if (success) {
                message.success('操作成功');
                setActiveModel('');
                loadNodes();
              }
            }}
            externalField={props.externalField}
          />
        );
      case 'edit':
        return (
          <ReportTreeNodeModal
            open
            data={item}
            current={props.current!}
            typeName={props.current?.typeName!}
            operateType="edit"
            handleCancel={() => {
              setActiveModel('');
              setItem(undefined);
            }}
            handleOk={(success: boolean) => {
              if (success) {
                message.success('操作成功');
                setActiveModel('');
                loadNodes();
              }
            }}
          />
        );
      case 'parent':
        return (
          <Modal
            {...commonModalProps}
            title="选择上级"
            onOk={async () => {
              try {
                let newParent: any = adjustmentNodeMap[parentId];
                if (!newParent) {
                  const loadedNodes = await props.current?.loadNodeById([parentId]);
                  if (!loadedNodes || loadedNodes.length === 0) {
                    message.error('选择的父节点不存在或未加载');
                    return;
                  }
                  newParent = loadedNodes.find((node) => node.id === parentId);
                  if (!newParent) {
                    message.error('选择的父节点不存在或未加载');
                    return;
                  }
                  setAdjustmentNodeMap((prev) => ({
                    ...prev,
                    [newParent!.id]: newParent!,
                  }));
                }

                let parent = newParent;
                while (parent) {
                  if (parent.id === item.id) {
                    message.error('所选节点及其下级不能是当前节点');
                    return;
                  }
                  parent = adjustmentNodeMap[parent.parentId!];
                }

                const newItem = _.cloneDeep(item);
                newItem.parentId = newParent.id;
                await props.current?.updateNode(item, newItem);

                const updatedNodes = await props.current?.loadChildrenSelect(
                  newParent.id,
                );
                if (updatedNodes) {
                  message.success('节点位置修改成功，路径已更新');
                }

                loadNodes();
              } catch (error) {
                message.error('操作失败，请重试');
              }
            }}
            okButtonProps={{ disabled: !parentId }}>
            <Row style={{ marginBottom: '16px' }}>
              <div>
                节点：<span>{item.name}</span>
              </div>
            </Row>
            <Row>
              <Breadcrumb style={{ marginBottom: '16px' }}>
                {getBreadcrumbPath(parentId).map((crumb, index) => (
                  <Breadcrumb.Item key={index}>
                    <a onClick={() => setParentId(crumb.id)}>{crumb.name}</a>
                  </Breadcrumb.Item>
                ))}
              </Breadcrumb>
            </Row>
            <Row
              className={cls['modal-tree']}
              style={{ height: '50vh', overflowY: 'auto' }}>
              <ReportTree
                current={props.current}
                nodes={buildTree(props.nodes)}
                loadChildren={props.loadChildren}
                onSelect={(_, info) => {
                  setParentId(info.node.id);
                }}
              />
            </Row>
          </Modal>
        );
      default:
        return null;
    }
  };

  return (
    <>
      <Tree<T>
        fieldNames={{ title: 'name', key: 'id', children: 'children' }}
        treeData={
          (props.currentTag || props.searchText) &&
          (props.currentTag !== 'total' || props.searchText !== '')
            ? (filterTreeData as T[])
            : (treeData as T[])
        }
        titleRender={treeTitleRender}
        expandedKeys={expandedKeys}
        onExpand={handleExpand}
        selectedKeys={selectedKeys}
        onSelect={handleSelect}
        loadData={loadTreeData}
        className={cls['tree-container']}
        checkable={props.checkable ?? false}
        onCheck={props.onCheck}
      />
      {loadReportTreeNodeModal()}
    </>
  );
};

export default ReportTree;
